gdk/win32/gdkevents-win32.c Force non-modal transient dialogs to iconify
authorCody Russell <cody@jhu.edu>
Thu, 18 Oct 2007 00:31:22 +0000 (00:31 +0000)
committerCody Russell <bratsche@src.gnome.org>
Thu, 18 Oct 2007 00:31:22 +0000 (00:31 +0000)
2007-10-17  Cody Russell  <cody@jhu.edu>

        * gdk/win32/gdkevents-win32.c
        * gdk/win32/gdkwindow-win32.[ch]: Force non-modal transient dialogs
        to iconify with their parents on Win32.  Maintain a list of transient
        children, and whenever a window is hidden or restored we now do the
        same thing to all connected transient windows above and below the
        current window in the chain.  See comment under WM_ACTIVATE for the
        reasons why.  (#164537, #371036, #405178)

svn path=/trunk/; revision=18929

ChangeLog
gdk/win32/gdkevents-win32.c
gdk/win32/gdkwindow-win32.c
gdk/win32/gdkwindow-win32.h

index 3fe5e9767e78a0ffb4d1ea2c3c95c3a807670532..3f81f71d435ae26ede4fdf70e81eacff6e69e628 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2007-10-17  Cody Russell  <cody@jhu.edu>
+
+       * gdk/win32/gdkevents-win32.c
+       * gdk/win32/gdkwindow-win32.[ch]: Force non-modal transient dialogs
+       to iconify with their parents on Win32.  Maintain a list of transient
+       children, and whenever a window is hidden or restored we now do the
+       same thing to all connected transient windows above and below the
+       current window in the chain.  See comment under WM_ACTIVATE for the
+       reasons why.  (#164537, #371036, #405178)
+
 2007-10-17  Owen Taylor  <otaylor@redhat.com>
 
        * gtk/Makefile.am (libgtk_win32_2_0_la_LDFLAGS): Move -Wl,-luuid
index 111551393219d21122c6d6b9df6aef2ce5688d05..a03833bda2ed7d0292c2af237db71ed07bfa3a85 100644 (file)
@@ -1266,6 +1266,37 @@ apply_filters (GdkWindow  *window,
   return result;
 }
 
+static void
+show_window_recurse (GdkWindow *window, gboolean hide_window)
+{
+  GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+  GSList *children = impl->transient_children;
+  GdkWindow *child = NULL;
+
+  if (!impl->changing_state)
+    {
+      impl->changing_state = TRUE;
+
+      if (children != NULL)
+       {
+         while (children != NULL)
+           {
+             child = children->data;
+             show_window_recurse (child, hide_window);
+
+             children = g_slist_next (children);
+           }
+       }
+
+      if (!hide_window)
+       ShowWindow (GDK_WINDOW_HWND (window), SW_RESTORE);
+      else
+       ShowWindow (GDK_WINDOW_HWND (window), SW_MINIMIZE);
+
+      impl->changing_state = FALSE;
+    }
+}
+
 static gboolean
 gdk_window_is_ancestor (GdkWindow *ancestor,
                        GdkWindow *window)
@@ -2826,15 +2857,17 @@ gdk_event_translate (MSG  *msg,
            {
              SetForegroundWindow (GDK_WINDOW_HWND (impl->transient_owner));
            }
-       }
 
-      if (event->any.type == GDK_UNMAP &&
-         p_grab_window == window)
-       gdk_pointer_ungrab (msg->time);
+         if (p_grab_window == window)
+           {
+             gdk_pointer_ungrab (msg->time);
+           }
 
-      if (event->any.type == GDK_UNMAP &&
-         k_grab_window == window)
-       gdk_keyboard_ungrab (msg->time);
+         if (k_grab_window == window)
+           {
+             gdk_keyboard_ungrab (msg->time);
+           }
+       }
 
       return_val = TRUE;
       break;
@@ -3331,6 +3364,49 @@ gdk_event_translate (MSG  *msg,
       break;
 
     case WM_ACTIVATE:
+      ;
+
+      /*
+       * On Windows, transient windows will not have their own taskbar entries.
+       * Because of this, we must hide and restore groups of transients in both
+       * directions.  That is, all transient children must be hidden or restored
+       * with this window, but if this window's transient owner also has a
+       * transient owner then this window's transient owner must be hidden/restored
+       * with this one.  And etc, up the chain until we hit an ancestor that has no
+       * transient owner.
+       *
+       * It would be a good idea if applications don't chain transient windows
+       * together.  There's a limit to how much evil GTK can try to shield you
+       * from.
+       */
+      GdkWindow *tmp_window = NULL;
+      GdkWindowImplWin32 *tmp_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+
+      while (tmp_impl->transient_owner != NULL)
+       {
+         tmp_window = tmp_impl->transient_owner;
+         tmp_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (tmp_window)->impl);
+       }
+
+      if (tmp_window == NULL)
+       tmp_window = window;
+
+      if (LOWORD (msg->wParam) == WA_INACTIVE && HIWORD (msg->wParam))
+        {
+         if (!tmp_impl->changing_state)
+           {
+             show_window_recurse (tmp_window, TRUE);
+           }
+        }
+      else if (LOWORD (msg->wParam) == WA_ACTIVE && HIWORD (msg->wParam))
+       {
+         if (!tmp_impl->changing_state)
+           {
+             show_window_recurse (tmp_window, FALSE);
+           }
+        }
+
+
       /* Bring any tablet contexts to the top of the overlap order when
        * one of our windows is activated.
        * NOTE: It doesn't seem to work well if it is done in WM_ACTIVATEAPP
index d0e2ee6cba25025e240195941cc9078b96e8447b..51db1c1669975ccb7c39e9a010b530de7fb0a744 100644 (file)
@@ -107,6 +107,9 @@ gdk_window_impl_win32_init (GdkWindowImplWin32 *impl)
   impl->type_hint = GDK_WINDOW_TYPE_HINT_NORMAL;
   impl->extension_events_selected = FALSE;
   impl->transient_owner = NULL;
+  impl->transient_children = NULL;
+  impl->num_transients = 0;
+  impl->changing_state = FALSE;
 }
 
 static void
@@ -831,6 +834,7 @@ _gdk_windowing_window_destroy (GdkWindow *window,
 {
   GdkWindowObject *private = (GdkWindowObject *)window;
   GdkWindowImplWin32 *window_impl = GDK_WINDOW_IMPL_WIN32 (private->impl);
+  GSList *tmp;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
   
@@ -840,6 +844,19 @@ _gdk_windowing_window_destroy (GdkWindow *window,
   if (private->extension_events != 0)
     _gdk_input_window_destroy (window);
 
+  /* Remove all our transient children */
+  tmp = window_impl->transient_children;
+  while (tmp != NULL)
+    {
+      GdkWindow *child = tmp->data;
+      GdkWindowImplWin32 *child_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (child)->impl);
+
+      child_impl->transient_owner = NULL;
+      tmp = g_slist_next (tmp);
+    }
+  g_slist_free (window_impl->transient_children);
+  window_impl->transient_children = NULL;
+
   /* Remove ourself from our transient owner */
   if (window_impl->transient_owner != NULL)
     {
@@ -1929,6 +1946,8 @@ gdk_window_set_transient_for (GdkWindow *window,
 {
   HWND window_id, parent_id;
   GdkWindowImplWin32 *window_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
+  GdkWindowImplWin32 *parent_impl = NULL;
+  GSList *item;
 
   g_return_if_fail (GDK_IS_WINDOW (window));
 
@@ -1951,7 +1970,32 @@ gdk_window_set_transient_for (GdkWindow *window,
       return;
     }
 
-  window_impl->transient_owner = parent;
+  if (parent == NULL)
+    {
+      GdkWindowImplWin32 *trans_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window_impl->transient_owner)->impl);
+      if (trans_impl->transient_children != NULL)
+        {
+          item = g_slist_find (trans_impl->transient_children, window);
+          item->data = NULL;
+          trans_impl->transient_children = g_slist_delete_link (trans_impl->transient_children, item);
+          trans_impl->num_transients--;
+
+          if (!trans_impl->num_transients)
+            {
+              trans_impl->transient_children = NULL;
+            }
+        }
+
+      window_impl->transient_owner = NULL;
+    }
+  else
+    {
+      parent_impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (parent)->impl);
+
+      parent_impl->transient_children = g_slist_append (parent_impl->transient_children, window);
+      parent_impl->num_transients++;
+      window_impl->transient_owner = parent;
+    }
 
   /* This changes the *owner* of the window, despite the misleading
    * name. (Owner and parent are unrelated concepts.) At least that's
@@ -2923,7 +2967,7 @@ QueryTree (HWND   hwnd,
           gint  *nchildren)
 {
   guint i, n;
-  HWND child;
+  HWND child = NULL;
 
   n = 0;
   do {
@@ -3407,7 +3451,7 @@ gdk_window_set_modal_hint (GdkWindow *window,
 
   private->modal_hint = modal;
 
-#if 0
+#if 1
   /* Not sure about this one.. -- Cody */
   if (GDK_WINDOW_IS_MAPPED (window))
     API_CALL (SetWindowPos, (GDK_WINDOW_HWND (window), 
@@ -3426,6 +3470,9 @@ gdk_window_set_skip_taskbar_hint (GdkWindow *window,
 
   g_return_if_fail (GDK_IS_WINDOW (window));
 
+  // ### TODO: Need to figure out what to do here.
+  return;
+
   GDK_NOTE (MISC, g_print ("gdk_window_set_skip_taskbar_hint: %p: %s\n",
                           GDK_WINDOW_HWND (window),
                           skips_taskbar ? "TRUE" : "FALSE"));
index 8a697565a45f0ad6536c6cd221aebfb78f206f70..8583ab35f37e0e6c04911e20781afc4762926d5a 100644 (file)
@@ -88,6 +88,9 @@ struct _GdkWindowImplWin32
   gboolean extension_events_selected;
 
   GdkWindow *transient_owner;
+  GSList    *transient_children;
+  gint       num_transients;
+  gboolean   changing_state;
 };
  
 struct _GdkWindowImplWin32Class